package com.party.mem.web.aop;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidPooledConnection;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.party.common.constant.Constant;
import com.party.common.utils.StringUtils;
import com.party.core.model.crowdfund.TargetProject;
import com.party.core.model.distributor.DistributorRelation;
import com.party.core.service.activity.IActivityService;
import com.party.core.service.crowdfund.ITargetProjectService;
import com.party.core.service.distributor.IDistributorRelationService;
import com.party.core.service.member.IMemberGroupService;
import com.party.mem.utils.RealmUtils;
import com.party.mem.web.annotation.ControlParam;
import com.party.mem.web.dto.AjaxResult;
import com.party.mem.web.security.CurrentUser;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.ModelAndView;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.List;
import java.util.Map;

/**
 * @Description: DataControlAop
 * @Author: yangshoukun
 * @Date: 2018/3/20 19:19
 */
@Component
@Aspect
public class DataControlAop {

    private static Logger logger = LoggerFactory.getLogger(DataControlAop.class);

    @Autowired
    private DruidDataSource druidDataSource;

    @Autowired
    private ITargetProjectService targetProjectService;

    @Autowired
    private IActivityService activityService;

    @Autowired
    private IDistributorRelationService distributorRelationService;

    @Autowired
    private IMemberGroupService memberGroupService;

    @Around("@annotation(com.party.mem.web.annotation.DataControl)")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        ResultSet ret = null;
        PreparedStatement ps = null;
        DruidPooledConnection connection = null;
        Method method = null;
        String sql = null;
        try {
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            method = signature.getMethod();
            Object[] params = joinPoint.getArgs();
            Annotation[][] methodAnnotations = method.getParameterAnnotations();
            int outLength = methodAnnotations.length;
            int inLength = 0;
            List<Map<String, Object>> paramList = Lists.newArrayList();

            if (outLength > 0) {
                outer:
                for (int i = 0; i < outLength; i++) {
                    inLength = methodAnnotations[i].length;
                    if (inLength < 1) {
                        continue;
                    }
                    for (int j = 0; j < inLength; j++) {
                        Annotation annotation = methodAnnotations[i][j];
                        if (annotation instanceof ControlParam) {
                            Object param = params[i] == null ? null : params[i];

                            Map<String, Object> map = Maps.newHashMap();
                            map.put("annotation", annotation);
                            map.put("param", param);

                            paramList.add(map);
                        }
                    }
                }
            }

            connection = druidDataSource.getConnection();

            for (Map<String, Object> map : paramList) {
                Annotation annotation = (Annotation) map.get("annotation");
                Object param = map.get("param");

                if (null != annotation && annotation instanceof ControlParam) {
                    CurrentUser user = RealmUtils.getNewCurrentUser();
                    List<String> orgIds = Lists.newArrayList();
                    if (user.isTwoLevelChildren()) {
                        orgIds.add(user.getPartnerId());
                    } else {
                        orgIds = memberGroupService.getChildWithMy(user.getId());
                    }

                    String table = ((ControlParam) annotation).table()[0];
                    String column = ((ControlParam) annotation).column()[0];
                    String getMethodName = ((ControlParam) annotation).getMethodName()[0];
                    boolean isProjectId = ((ControlParam) annotation).isProjectId()[0];
                    boolean isRequired = ((ControlParam) annotation).isRequired()[0];
                    boolean isDistribution = ((ControlParam) annotation).isDistribution()[0];

                    if (null != param) {
                        String strParam = null;
                        if (param instanceof String) {
                            strParam = param.toString();
                        } else {
                            Class clazz = param.getClass();
                            Method getMethod = clazz.getMethod(getMethodName);
                            strParam = getMethod.invoke(param) == null ? null : getMethod.invoke(param).toString();

                            // 事件和众筹用同一个分析接口, 通过同一个实体传的不同参数
                            if (StringUtils.isEmpty(strParam) && ((ControlParam) annotation).table().length > 1) {
                                table = ((ControlParam) annotation).table()[1];
                                column = ((ControlParam) annotation).column()[1];
                                isProjectId = ((ControlParam) annotation).isProjectId()[1];
                                getMethodName = ((ControlParam) annotation).getMethodName()[1];
                                getMethod = clazz.getMethod(getMethodName);
                                strParam = getMethod.invoke(param) == null ? null : getMethod.invoke(param).toString();
                            }
                        }

                        // 如果是众筹id
                        if (isProjectId) {
                            TargetProject targetProject = targetProjectService.findByProjectId(strParam);
                            if (null == targetProject || StringUtils.isEmpty(targetProject.getTargetId())) {

                            } else {
                                strParam = targetProject.getTargetId();
                            }
                        }

                        // 是否是分销关系id
                        if (isDistribution) {
                            DistributorRelation distributorRelation = distributorRelationService.get(strParam);
                            if (null != distributorRelation) {
                                strParam = distributorRelation.getTargetId();
                            }
                        }

                        if (StringUtils.isNotEmpty(strParam)) {
                            StringBuilder sqlBuilder = new StringBuilder(" select * from ");
                            sqlBuilder.append(table);
                            // 如果是合伙人的那张表单独处理
                            if (table.equals("co_target_copartner")) {
                                sqlBuilder.append(" where target_id = '").append(strParam).append("' and ");
                            } else if (table.equals("partner_member")) {
                                sqlBuilder.append(" where ");
                            } else {
                                sqlBuilder.append(" where id = '").append(strParam).append("' and ");
                            }
                            sqlBuilder.append(column);
                            sqlBuilder.append(" in ( ");
                            for (int i = 0; i < orgIds.size(); i++) {
                                sqlBuilder.append(" '" + orgIds.get(i) + "' ");
                                if (i != orgIds.size() - 1) {
                                    sqlBuilder.append(" , ");
                                }
                            }
                            sqlBuilder.append(" )");

                            sql = sqlBuilder.toString();

                            ps = connection.prepareCall(sql);
                            ret = ps.executeQuery();
                            if (null == ret || !ret.next()) {
                                return getReturnObject(method);
                            }
                        } else {
                            if (StringUtils.isNotEmpty(column) && StringUtils.isNotEmpty(table) && isRequired) {
                                return getReturnObject(method);
                            }
                        }
                    } else if (isRequired) {
                        return getReturnObject(method);
                    }
                }
            }
        } catch (Exception e) {
            logger.error("数据权限控制异常. 方法为: {} sql为: {}",
                    method.getDeclaringClass().getName() + "." + method.getName(), sql);
        } finally {
            if (null != ret) {
                ret.close();
            }
            if (null != ps) {
                ps.close();
            }
            if (null != connection) {
                connection.close();
            }
        }

        Object result = joinPoint.proceed();
        return result;
    }

    /**
     * 获取返回的结果
     *
     * @param method 方法
     * @return 返回的结果
     */
    public Object getReturnObject(Method method) {
        Class returnTypeClazz = method.getReturnType();
        if (ModelAndView.class.getName().equals(returnTypeClazz.getName())) {
            ModelAndView mv = new ModelAndView(Constant.ERROR_402);
            return mv;
        } else if (AjaxResult.class.getName().equals(returnTypeClazz.getName())) {
            AjaxResult ajaxResult = new AjaxResult();
            ajaxResult.setSuccess(false);
            ajaxResult.setDescription("您没有权限进行此操作");
            return ajaxResult;
        }
        return null;
    }
}
